package com.linkwechat.common.utils;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * @Author 王君平
 * @Date 2023/8/29 21:25
 * @Description
 */
@Slf4j
public class MapUtil {

    /**
     * 将一个 JavaBean 对象转化为一个 Map  如果对象里面有嵌套对象，则对嵌套象转为json
     * @param bean 要转化的JavaBean 对象
     * @return 转化出来的 Map 对象
     * @throws IntrospectionException 如果分析类属性失败
     * @throws IllegalAccessException 如果实例化 JavaBean 失败
     * @throws InvocationTargetException 如果调用属性的 setter 方法失败
     */
    public static Map<String, String> toMap(Object bean) {
        Map<String,String> returnMap = new HashMap<>();
        Class<? extends Object> clazz = bean.getClass();
        BeanInfo beanInfo = null;
        try {
            beanInfo = Introspector.getBeanInfo(clazz);
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (int i = 0; i < propertyDescriptors.length; i++) {
                PropertyDescriptor descriptor = propertyDescriptors[i];
                String propertyName = descriptor.getName();
                if (!propertyName.equals("class")) {
                    Method readMethod = descriptor.getReadMethod();
                    Object value = null;
                    value = readMethod.invoke(bean, new Object[0]);
                    String strValue = null;
                    if (null != value) {
                        if(value instanceof Object){
                            if(!(value instanceof Number)  && !(value instanceof String)){
                                strValue = JSON.toJSONString(value);
                            }
                        }
                        if(StringUtil.isNotEmpty(strValue)){
                            returnMap.put(propertyName, strValue);
                        }else {
                            returnMap.put(propertyName, value.toString());
                        }
                    }
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return returnMap;
    }

    /**
     * 将一个 JavaBean 对象转化为一个 Map  如果对象里面有嵌套对象，则对嵌套象转为json
     * @param bean 要转化的JavaBean 对象
     * @return 转化出来的 Map 对象
     * @throws IntrospectionException 如果分析类属性失败
     * @throws IllegalAccessException 如果实例化 JavaBean 失败
     * @throws InvocationTargetException 如果调用属性的 setter 方法失败
     */
    public static Map<String, Object> toMapObject(Object bean) {
        Map<String,Object> returnMap = new HashMap<>();
        Class<? extends Object> clazz = bean.getClass();
        BeanInfo beanInfo = null;
        try {
            beanInfo = Introspector.getBeanInfo(clazz);
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (int i = 0; i < propertyDescriptors.length; i++) {
                PropertyDescriptor descriptor = propertyDescriptors[i];
                String propertyName = descriptor.getName();
                if (!propertyName.equals("class")) {
                    Method readMethod = descriptor.getReadMethod();
                    Object value = null;
                    value = readMethod.invoke(bean, new Object[0]);
                    if (null != value) {
                        returnMap.put(propertyName, value);
                    }
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return returnMap;
    }

    public static <T> T getBeanFromMap(Map<String,Object> map,Class<T> clazz) {
        if(map==null||map.size()==0||clazz==null) {
            return null;
        }
        map = getACleanNullMap(map);
        T t;
        try {
            t = clazz.newInstance();
            BeanUtils.populate(t, map);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return t;
    }

    public static Map<String,Object> getACleanNullMap(Map<String,Object> map){
        if(map==null||map.size()==0) {
            return null;
        }
        Map<String,Object> cleanMap = new HashMap<>();
        Iterator<Map.Entry<String,Object>> iterator =   map.entrySet().iterator();
        while(iterator.hasNext()){
            Map.Entry<String,Object> entry = iterator.next();
            String key = entry.getKey();
            Object value = entry.getValue();
            if(value==null) {
                continue;
            }
            if(value.getClass().getSimpleName().equals("java.lang.String")) {
                String strValue = (String) value;
                if(strValue!=null||!strValue.trim().isEmpty()||!strValue.trim().equals("null")) {
                    cleanMap.put(key, value);
                }
            }else {
                cleanMap.put(key, value);
            }
        }
        return cleanMap;
    }


    public static void mapCleanNull(Map<String,Object> map){
        if(map==null||map.size()==0) {
            return;
        }
        Iterator<Map.Entry<String,Object>> iterator =   map.entrySet().iterator();
        while(iterator.hasNext()){
            Map.Entry<String,Object> entry = iterator.next();
            String key = entry.getKey();
            Object value = entry.getValue();
            if(value==null) {
                continue;
            }
            String strValue = String.valueOf(value);
            if(strValue==null||strValue.trim().isEmpty()||strValue.trim().equalsIgnoreCase("null")) {
                map.put(key, null);
            }
        }
    }

    /** 不要轻易更改此类的实现  因为支付用到了
     * 将一个 JavaBean 对象转化为一个 Map
     * @param bean 要转化的JavaBean 对象
     * @return 转化出来的 Map 对象
     * @throws IntrospectionException 如果分析类属性失败
     * @throws IllegalAccessException 如果实例化 JavaBean 失败
     * @throws InvocationTargetException 如果调用属性的 setter 方法失败
     */
    public static Map<String, String> toForWxPayMap(Object bean) {
        Class<? extends Object> clazz = bean.getClass();
        Map<String, String> returnMap = new HashMap<>() ;
        BeanInfo beanInfo = null;
        try {
            beanInfo = Introspector.getBeanInfo(clazz);
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (int i = 0; i < propertyDescriptors.length; i++) {
                PropertyDescriptor descriptor = propertyDescriptors[i];
                String propertyName = descriptor.getName();
                if (!propertyName.equals("class")) {
                    Method readMethod = descriptor.getReadMethod();
                    Object value = null;
                    value = readMethod.invoke(bean, new Object[0]);
                    if (null != propertyName) {
                        propertyName = propertyName.toString();
                    }
                    if (null != value) {
                        returnMap.put(propertyName, value.toString());
                    }
                }
            }
        } catch (IntrospectionException e) {
            log.error("分析类属性失败");
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            log.error("实例化 JavaBean 失败");
            throw new RuntimeException(e);
        } catch (IllegalArgumentException e) {
            log.error("映射错误");
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            log.error("调用属性的 setter 方法失败");
            throw new RuntimeException(e);
        }
        return returnMap;
    }
}
